/*
 * CircleSlice.cpp
 *
 *  Created on: 05-01-2011
 *      Author: Piotr
 */

#include "geometry/CircleSlice.hpp"
#include "geometry/Line.hpp"
#include "pch.hpp"

CircleSlice::CircleSlice(const Vector& position, float r, float angle, float openingAngle) :
	position(position), r(r), angle(angle), openingAngle(openingAngle)
{

}

bool CircleSlice::containsPartially(const geometry::Rectangle& rectangle) const
{
	if(contains(rectangle.getPosition()) || contains(rectangle.getPosition() + Vector(
			rectangle.getSize().getWidth(), 0.0f)) || contains(rectangle.getPosition() + Vector(0.0f,
			rectangle.getSize().getHeight())) || contains(rectangle.getPosition() + Vector(
			rectangle.getSize().getWidth(), rectangle.getSize().getHeight())))
	{
		return true;
	}

	const Vector& minEndPoint = getMinEndPoint();
	const Vector& maxEndPoint = getMaxEndPoint();

	if(rectangle.contains(minEndPoint) || rectangle.contains(maxEndPoint))
	{
		return true;
	}
	return false;
}

bool CircleSlice::contains(const Vector& point) const
{
	if((point - position).getSquaredLength() > r * r)
	{
		return false;
	}

	const Vector& minAngleVec = getMinEndPoint();
	const Vector& maxAngleVec = getMaxEndPoint();

	const Line& minAngleLine = Line(minAngleVec, position);
	const Line& maxAngleLine = Line(position, maxAngleVec);

	const Line::SIDE_IN_CCW sideMin = minAngleLine.getSide(point);
	const Line::SIDE_IN_CCW sideMax = maxAngleLine.getSide(point);

	if(openingAngle <= MathUtils::toRadians(180.0f))
	{
		return sideMin == Line::POSITIVE && sideMax == Line::POSITIVE;
	}

	return !(sideMin == Line::NEGATIVE && sideMax == Line::NEGATIVE);
}

const Vector& CircleSlice::getPosition() const
{
	return position;
}

void CircleSlice::setPosition(const Vector& position)
{
	this->position = position;
}

float CircleSlice::getRadius() const
{
	return r;
}

void CircleSlice::setRadius(float r)
{
	this->r = r;
}

float CircleSlice::getAngle() const
{
	return angle;
}

void CircleSlice::setAngle(float angle)
{
	this->angle = angle;
}

float CircleSlice::getOpeningAngle() const
{
	return openingAngle;
}

void CircleSlice::setOpeningAngle(float openingAngle)
{
	this->openingAngle = openingAngle;
}

float CircleSlice::getMinAngleInRadians() const
{
	return angle - openingAngle / 2;
}

float CircleSlice::getMaxAngleInRadians() const
{
	return angle + openingAngle / 2;
}

Vector CircleSlice::getMinEndPoint() const
{
	const float minAngle = getMinAngleInRadians();
	const Vector& direction = Vector(cosf(minAngle), sinf(minAngle));

	return position + direction * r;
}

Vector CircleSlice::getMaxEndPoint() const
{
	const float maxAngle = getMaxAngleInRadians();
	const Vector& direction = Vector(cosf(maxAngle), sinf(maxAngle));

	return position + direction * r;
}
